export function consume:
    &(chat::#Service) => Async
    &(session) =>
        { sys::println 'connected' }
            . { concat-map &() => { session.receive-messages () } }
            . { concat-map &(msg) =>
                { sys::println { "?: ?" (msg.from, msg.content.text) } } }
            . { wait-complete }
            . { crash-on-error }
            . { with
                let read-and-send :=
                    \ await let text := { sys::scanln '' },
                    \ await { session.say { text } },
                    { return () },
                read-and-send.{forever}.{crash-on-error} };

entry
    let login-and-chat :=
        \ await let nickname := { sys::scanln '(login) nickname: ' },
        { rpc::access {
            service: chat::#Service,
            backend: chat::DefaultClientBackend,
            options: {},
            argument: { nickname },
            consumer: &(session) => { consume session }
        } },
    login-and-chat
        . { catch-retry &(err) =>
            let kind := ((err get chat::ERR_KIND) ?? ''),
            if (kind = chat::ERR_NAME_IN_USE):
                \ await { sys::println '*** This name is in use. Try another.' }
                    . { crash-on-error },
                { return Yes },
            else:
                { return No }
        }
        . { crash-on-error };
